;改进:
;用户按下1~9任意键后 灯对应闪烁1~9次 每闪烁一次 都会输出Lamb!
;将闪烁处理代码利用循环合并成了一段 代码量大大缩减
;完善了一系列用户交互过程中的友好型信息输出 为输入后侧加入了换行
DATA SEGMENT
;-接口区-
IO8253A EQU 280H              ;计数器0地址
IO8253B EQU 281H              ;计数器1地址
IO8253C EQU 282H              ;计数器2地址
IO8253D EQU 283H              ;8253控制端口
;-提示信息区-
HC  DB 0AH,0DH,'$'            ;回车换行 用于接收用户输入后进行换行输出
TS  DB 'Press 1~9, lamb the same times',0AH,0DH   ;菜单
    DB 'Press q, quit',0AH,0DH,'$'
ER  DB 'wrong key!',0AH,0DH,'$' ;提示用户按键错误 
WAT DB 'Task is processing, please wait for a short time.',0AH,0DH,'$';提示用户等待
FNS DB 'Task has finished.',0AH,0DH,'$'   ;提示用户某任务结束了
TC DB 'Over',0AH,0DH,'$'           ;程序结束提示
TB DB 'Lamb!',0AH,0DH,'$'         ;亮一下 输出一次
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
      ;数据段初始化
      MOV AX,DATA 
      MOV DS,AX
      
;ZL 择路 接收按键跳转指定模块
      ;输出菜单
ZL:   LEA DX,TS
      MOV AH,9
      INT 21H 
      ;键盘输入一个字符 存ASCII到AL
      MOV AH,1
      INT 21H 
      ;输出换行
      LEA DX,HC
      MOV AH,9
      INT 21H
      ;对键盘输入的字符进行比较
      CMP AL,71H    
      JZ JIESHU     ;字符是q结束
      CMP AL,31H
      JB  WRG        ;字符ASCII小于1 判错
      CMP AL,39H    
      JA WRG         ;字符ASCII大于9 判错
      ;用户输入的是1~9
      MOV CX,0
      MOV CL,AL     ;ASCII值给CX
      MOV BX,30H     
      SUB CX,BX      ;将ASCII转为对应数值
      JMP L         ;跳到L 执行闪烁任务
 ;WRG 用户输入了错误的按键
      ;提示 错误输入
WRG:  LEA DX,ER
      MOV AH,9
      INT 21H
      ;跳ZL 用户重新输入
      JMP ZL        
 
; L 亮一下
L:    ;提示用户等待
      LEA DX,WAT 
      MOV AH,9
      INT 21H
      ;向8253控制端口写30H(0011 0000) 设置(00)计数器0 工作方式 
      ;(11)先读写低字节 (000)方式零 (0)二进制数制
      MOV DX,IO8253D
      MOV AL,30H
      OUT DX,AL
      ;进入闪烁循环 CX保存的是灯闪烁几次
L1:   PUSH CX
      ;向计数器0写计数器初值0AAAAH
      MOV DX,IO8253A
      MOV AL,0AAH
      OUT DX,AL
      OUT DX,AL
      ;输出Lamb!
      LEA DX,TB 
      MOV AH,9
      INT 21H
      ;最后一次闪烁 其后无需等待时间
      CMP CX,1
      JZ L1END
      ;延时 (CX)*(BX)个DEC指令时间
       MOV CX,0FFFFH
WAIT1: MOV BX,100H
WAIT2: DEC BX
       JNZ WAIT2
       LOOP WAIT1
      ;闪烁计次出栈
      POP CX
L1END: LOOP L1
      ;提示用户已经完成闪烁任务
      LEA DX,FNS 
      MOV AH,9
      INT 21H
      ;跳回ZL
      JMP ZL

;JIESHU 结束
        ;输出结束信息 over
JIESHU: LEA DX,TC
        MOV AH,9
        INT 21H 
        ;退出程序
        MOV AH,4CH
        INT 21H
CODE ENDS
END START